<template>
  <div ref='resizer_container' class="resizer_container" @contextmenu.stop.prevent>
    <div ref="container" class="canvas_container" @contextmenu.stop.prevent>
      <canvas ref="cutImg" :width="imgZoomSize.width" :height="imgZoomSize.height" class="cut_img"
              :style="containerDistance" @pointerdown="setCutBoxLoc"/>
      <div class="mask_layer" :style="[imgSize,containerDistance]" v-if="isCuted">
        <slide-element ref="slideElement"
                       :ContainerSize="imgZoomSize"
                       :ElementStyle="{border:'1px solid'}"
                       :Location="loc"
                       :Size="size"
                       :Activated=true
                       :ShowContextMenu=false
                       @appended="appended"
                       @LocSizeChanging="paintImage"
                       @LocSizeChanged="isShowToolBar=true">
          <canvas id="cutBox" ref="cutBox" :width="cutBoxSize.width" :height="cutBoxSize.height"
                  @contextmenu.stop.prevent/>

          <div class="cut_box_bar" v-show="isShowToolBar">
            <ul>
              <li @click="cancel">
                <img src="~@/assets/img/SlideEditor/ImageResizer/canel.png">
                <span>取消</span>
              </li>
              <li @click="cutImage">
                <img src="~@/assets/img/SlideEditor/ImageResizer/finish.png">
                <span>裁剪</span>
              </li>
              <li @click="mosaicImage">
                <img src="~@/assets/img/SlideEditor/ImageResizer/mosaic.png">
                <span>模糊</span>
              </li>
            </ul>
          </div>
        </slide-element>
      </div>
    </div>
  </div>
</template>
<script>
  import SlideElement from './SlideElement'
  import events from '../../common/typeEvents'

  let imgCanvasContext = null
  let cutCanvasContext = null
  export default {
    name: 'SlideImageResizer',
    data: function () {
      return {
        signs: [],
        operation: 0,
        fillImage: null,
        isCuted: false,
        isShowToolBar: false,
        zoomScale: 1,
        imgFullSize: {width: 0, height: 0},
        cutBoxSize: {width: 0, height: 0},
        containerDistance: {top: '0px', left: '0px'}, // 容器边距
        loc: {top: 0, left: 0},
        size: {width: 0, height: 0},
        cropImage: null
      }
    },
    props: {image: {type: String}, signStyle: {type: Object}},
    components: {
      'slide-element': SlideElement
    },
    mounted: function () {
      this.$eventBus.$on(events.ImageResizerToolBar.ImageZoomIn, this.zoomIn)
      this.$eventBus.$on(events.ImageResizerToolBar.ImageZoomOut, this.zoomOut)
      this.$eventBus.$on(events.ImageResizerToolBar.ImageRestoration, this.restoration)
      this.$eventBus.$on(events.ImageResizerToolBar.ImageFill, this.finishCropImg)
      this.$eventBus.$on(events.ImageResizerToolBar.ImageReplace, this.replaceCropImg)
      this.$eventBus.$on(events.ImageResizerToolBar.OperationChange, (state) => {
        this.operation = state
      })
      this.$nextTick(function () {
        this.initImageAutoSize(this.image)
      })
    },

    watch: {
      image: function (n, o) {
        this.initImageAutoSize(n)
      }
    },
    computed: {
      imgSize: function () {
        return {
          width: `${this.imgZoomSize.width}px`,
          height: `${this.imgZoomSize.height}px`
        }
      },
      imgZoomSize: function () {
        return {
          width: this.imgFullSize.width * this.zoomScale,
          height: this.imgFullSize.height * this.zoomScale
        }
      }
    },
    methods: {
      appended: function () {
        if (this.cutBoxSize.width && this.cutBoxSize.height) return

        let size = {width: 0.3 * this.imgZoomSize.width, height: 0.3 * this.imgZoomSize.height}

        let loc = {left: parseFloat(this.loc.left), top: parseFloat(this.loc.top)}

        if (loc.left - size.width / 2 < 0) {
          loc.left = 0
        } else if (loc.left + size.width / 2 > this.imgZoomSize.width) {
          loc.left = this.imgZoomSize.width - size.width
        } else {
          loc.left = loc.left - size.width / 2
        }

        if (loc.top - size.height / 2 < 0) {
          loc.top = 0
        } else if (loc.top + size.height / 2 > this.imgZoomSize.height) {
          loc.top = this.imgZoomSize.height - size.height
        } else {
          loc.top = loc.top - size.height / 2
        }
        this.size = {width: `${size.width}px`, height: `${size.height}px`}
        this.loc = {left: `${loc.left}px`, top: `${loc.top}px`}
        this.paintImage({...size, ...loc})
      },
      paintImage: function (locSize) {
        // let self = this
        let canvas = this.$refs.cutBox
        if (!canvas || !locSize) return
        this.cutBoxSize.width = locSize.width
        this.cutBoxSize.height = locSize.height

        this.$nextTick(function () {
          if (!cutCanvasContext) {
            cutCanvasContext = canvas.getContext('2d')
          } else {
            cutCanvasContext.clearRect(
              0,
              0,
              canvas.clientWidth,
              canvas.clientHeight
            )
          }
          if (locSize.width && locSize.height) {
            let cutImg = imgCanvasContext.getImageData(
              locSize.left,
              locSize.top,
              locSize.width,
              locSize.height
            )

            // 将图片绘制到画布上
            cutCanvasContext.putImageData(cutImg, 0, 0)
          }
        })
      },
      initImageAutoSize: function (imgUrl) {
        let self = this
        let container = self.$refs.container
        if (!container) return

        let image = new Image()
        image.src = imgUrl
        image.onload = function () {
          // 当图片比图片框小时不做任何改变
          if (
            image.width < container.clientWidth &&
            image.height < container.clientHeight
          ) {
            self.imgFullSize.width = image.width
            self.imgFullSize.height = image.height
          } else {
            if (
              container.clientWidth / container.clientHeight <=
              image.width / image.height
            ) {
              // 原图片宽高比例 大于 图片框宽高比例
              self.imgFullSize.width = container.clientWidth
              // 以框的宽度为标准
              self.imgFullSize.height =
                container.clientWidth * (image.height / image.width)
            } else {
              // 原图片宽高比例 小于 图片框宽高比例
              self.imgFullSize.width =
                container.clientHeight * (image.width / image.height)
              // 以框的高度为标准
              self.imgFullSize.height = container.clientHeight
            }
          }
          self.$nextTick(function () {
            let canvas = self.$refs.cutImg
            if (!imgCanvasContext) {
              imgCanvasContext = canvas.getContext('2d')
            } else {
              imgCanvasContext.clearRect(
                0,
                0,
                canvas.clientWidth,
                canvas.clientHeight
              )
            }
            let left = (container.clientWidth - self.imgZoomSize.width) / 2
            let top = (container.clientHeight - self.imgZoomSize.height) / 2
            self.containerDistance['left'] = left >= 0 ? `${left}px` : '0px'
            self.containerDistance['top'] = top >= 0 ? `${top}px` : '0px'
            image.width = self.imgZoomSize.width
            image.height = self.imgZoomSize.height
            self.fillImage = image

            self.drawSign()
            // 将图片绘制到画布上
            // imgCanvasContext.drawImage(image, 0, 0, image.width, image.height)
          })
        }
      },
      cutImage: function () {
        let cutBox = this.$refs.cutBox
        if (!cutBox) return
        this.zoomScale = 1
        this.image = cutBox.toDataURL()
        this.initImageAutoSize(this.image)
        this.size = this.cutBoxSize = {width: 0, height: 0}
        this.isCuted = this.isShowToolBar = false
        cutCanvasContext = null
      },
      finishCropImg: function () {
        if (this.isCuted) return this.$message({message: '裁剪过程中无法进行该操作', type: 'warning'})

        let cutImg = this.$refs.cutImg
        if (!cutImg) return
        this.$emit('FinishCropImg', {
          url: cutImg.toDataURL(),
          width: cutImg.clientWidth,
          height: cutImg.clientHeight
        })
      },
      replaceCropImg: function () {
        if (this.isCuted) return this.$message({message: '裁剪过程中无法进行该操作', type: 'warning'})

        let cutImg = this.$refs.cutImg
        if (!cutImg) return
        this.$emit('replaceCropImg', cutImg.toDataURL())
      },
      mosaicImage: function () {
        let el = this.$refs.slideElement
        let oImg = imgCanvasContext.getImageData(
          el.elLocation.left,
          el.elLocation.top,
          el.elSize.width,
          el.elSize.height
        )

        // 马赛克的程度，数字越大越模糊
        let num = 10
        // 等分画布
        let stepW = oImg.width / num
        let stepH = oImg.height / num
        // 这里是循环画布的像素点
        for (let i = 0; i < stepH; i++) {
          for (let j = 0; j < stepW; j++) {
            // 获取一个小方格的随机颜色，这是小方格的随机位置获取的

            let x = j * num + Math.floor(Math.random() * num)
            let y = i * num + Math.floor(Math.random() * num)

            let color = [
              oImg.data[4 * (y * oImg.width + x)],
              oImg.data[4 * (y * oImg.width + x) + 1],
              oImg.data[4 * (y * oImg.width + x) + 2],
              oImg.data[4 * (y * oImg.width + x) + 3]
            ]

            // 这里是循环小方格的像素点，
            for (let k = 0; k < num; k++) {
              for (let l = 0; l < num; l++) {
                x = j * num + l
                y = i * num + k
                // 设置小方格的颜色
                oImg.data[4 * (y * oImg.width + x)] = color[0]
                oImg.data[4 * (y * oImg.width + x) + 1] = color[1]
                oImg.data[4 * (y * oImg.width + x) + 2] = color[2]
                oImg.data[4 * (y * oImg.width + x) + 3] = color[3]
              }
            }
          }
        }
        imgCanvasContext.putImageData(oImg, el.elLocation.left, el.elLocation.top)

        this.image = this.$refs.cutImg.toDataURL()
        this.initImageAutoSize(this.image)
        this.size = this.cutBoxSize = {width: 0, height: 0}
        this.isCuted = this.isShowToolBar = false
        cutCanvasContext = null
      },
      // 放大图片
      zoomIn: function () {
        if (this.isCuted) return this.$message({message: '裁剪过程中无法进行该操作', type: 'warning'})

        let canvas = this.$refs.cutImg
        if (this.zoomScale >= 3 || !canvas) return
        this.zoomScale += 0.1
        this.initImageAutoSize(this.image)
      },
      // 缩小图片
      zoomOut: function () {
        if (this.isCuted) return this.$message({message: '裁剪过程中无法进行该操作', type: 'warning'})

        let canvas = this.$refs.cutImg
        if (this.zoomScale <= 0.2 || !canvas) return
        this.zoomScale -= 0.1
        this.initImageAutoSize(this.image)
      },
      // 重置图片大小
      restoration: function () {
        if (this.isCuted) return this.$message({message: '裁剪过程中无法进行该操作', type: 'warning'})

        let canvas = this.$refs.cutImg
        if (!canvas) return
        this.zoomScale = 1
        this.initImageAutoSize(this.image)
      },
      setCutBoxLoc: function () {
        // 获取容器的浏览器坐标
        let cutImg = this.$refs.cutImg
        let container = this.$refs.resizer_container
        if (!cutImg || !container) return
        let cutImgLoc = cutImg.getBoundingClientRect()
        // 获取鼠标点击时对于容器的坐标
        let loaction = {
          x: event.clientX < cutImg.left ? 0 : event.clientX - cutImgLoc.left,
          y: event.clientY < cutImg.top ? 0 : event.clientY - cutImgLoc.top
        }
        this.loc = {left: `${loaction.x}px`, top: `${loaction.y}px`}
        if (this.operation === 0) {
          this.isCuted = true
          this.$nextTick(function () {
            let slideElement = this.$refs.slideElement
            if (slideElement) slideElement.setDragDirection('setLowerRightCorner')
          })
        } else {
          let self = this
          let sign = {type: 'free', points: [{x: loaction.x / self.zoomScale, y: loaction.y / self.zoomScale}]}
          this.signs.push(sign)
          event.target.onpointermove = function () {
            if (event.buttons !== 1) return
            if (self.operation === 1) {
              sign.type = 'free'
              sign.points.push({x: event.offsetX / self.zoomScale, y: event.offsetY / self.zoomScale})
            } else if (self.operation === 2) {
              sign.type = 'line'
              sign.points[1] = {x: event.offsetX / self.zoomScale, y: event.offsetY / self.zoomScale}
            } else if (self.operation === 3) {
              sign.type = 'rect'
              sign.points[0] = {
                ...sign.points[0],
                w: event.offsetX / self.zoomScale - sign.points[0].x,
                h: event.offsetY / self.zoomScale - sign.points[0].y
              }
            }
            // else if (self.operation === 4) {
            //   sign.type = 'ellipse'
            //   let x = (loaction.x + event.offsetX / 2) * self.zoomScale
            //   let y = (loaction.y + event.offsetY / 2) * self.zoomScale
            //   debugger
            //   sign.points[0] = {
            //     x, y,
            //     r: Math.abs(x > y ? x / 2 : y / 2)
            //   }
            // }
            self.drawSign()
          }

          event.target.onpointerup = event.target.onpointerout = () => {
            event.target.onpointermove = null
          }
        }
      },
      cancel: function () {
        this.size = this.cutBoxSize = {width: 0, height: 0}
        this.isCuted = this.isShowToolBar = false
        cutCanvasContext = null
      },
      drawSign (sign) {
        imgCanvasContext.clearRect(0, 0, this.imgZoomSize.width, this.imgZoomSize.height)
        imgCanvasContext.drawImage(this.fillImage, 0, 0, this.fillImage.width, this.fillImage.height)
        imgCanvasContext.lineWidth = parseInt(this.signStyle.width) || 2
        imgCanvasContext.strokeStyle = this.signStyle.color || 'red'
        let signs = sign ? [sign] : this.signs
        for (let i = 0; i < signs.length; i++) {
          imgCanvasContext.beginPath()
          if (signs[i].type === 'free') {
            for (let j = 0; j < signs[i].points.length; j++) {
              let item = signs[i].points[j]
              imgCanvasContext.lineTo(item.x * this.zoomScale, item.y * this.zoomScale)
              imgCanvasContext.moveTo(item.x * this.zoomScale, item.y * this.zoomScale)
            }
          } else if (signs[i].type === 'line') {
            imgCanvasContext.moveTo(signs[i].points[0].x * this.zoomScale, signs[i].points[0].y * this.zoomScale)
            imgCanvasContext.lineTo(signs[i].points[1].x * this.zoomScale, signs[i].points[1].y * this.zoomScale)
          } else if (signs[i].type === 'rect') {
            imgCanvasContext.rect(signs[i].points[0].x * this.zoomScale, signs[i].points[0].y * this.zoomScale, signs[i].points[0].w * this.zoomScale, signs[i].points[0].h * this.zoomScale)
          }
          // else if (signs[i].type == 'ellipse') {
          //     let r = (signs[i].points[0].r >= 0 ? signs[i].points[0].r : 0) * this.zoomScale
          //     let ratioX = signs[i].points[0].x * this.zoomScale / r
          //     let ratioY = signs[i].points[0].y * this.zoomScale / r
          //     imgCanvasContext.arc(signs[i].points[0].x * this.zoomScale / ratioX, signs[i].points[0].y * this.zoomScale / ratioY, r, 0, 2 * Math.PI, false)
          //   }

          imgCanvasContext.closePath()
          imgCanvasContext.stroke()
        }
      }
    },
    beforeDestroy: function () {
      imgCanvasContext = null
      cutCanvasContext = null
    }
  }
</script>
<style>
  .resizer_container {
    width: 100%;
    height: 100%;
    background-color: #fff;
    position: relative;
    overflow: auto;
  }

  .resizer_container .canvas_container {
    width: 100%;
    height: 100%;
    position: absolute;
  }

  .resizer_container .cut_img {
    position: relative;
  }

  .resizer_container .mask_layer {
    position: absolute;
    background-color: rgba(167, 167, 167, 0.753);
  }

  .resizer_container .mask_layer .cut_box_bar {
    min-width: 300px;
    height: 30px;
    float: right;
  }

  .resizer_container .mask_layer .cut_box_bar ul {
    margin: 0 auto;
  }

  .resizer_container .mask_layer .cut_box_bar ul li {
    width: 55px;
    height: 27px;
    line-height: 25px;
    color: #0682d4;
    list-style: none;
    cursor: pointer;
    float: right;
    margin: 0 2px;
    border: 1px solid;
    border-radius: 4px;
    background: white;
  }

  .resizer_container .mask_layer .cut_box_bar ul img {
    /*width: 12px;*/
    /*height: 12px;*/
    /*margin-left: 2px;*/
    height: 100%;
    padding: 8px;
    padding-right: 5px;
  }

  .resizer_container .mask_layer .cut_box_bar ul li span {
    font-size: 12px;
  }

  .resizer_container .box {
    zoom: 0.5;
  }
</style>
